package com.ljwm.jsydfw;

import com.xiaoleilu.hutool.http.HttpUtil;
import com.xiaoleilu.hutool.json.JSONObject;
import com.xiaoleilu.hutool.json.JSONUtil;
import com.xiaoleilu.hutool.lang.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by yuzhou on 2017/12/25.
 */
public class JsydfwClient {

  private static final Logger _log = LoggerFactory.getLogger(JsydfwClient.class);

  public static JsydfwClient inst = null;

  /**
   * 初始化前置应用通讯客户端
   * @param appId
   * @param appSecret
   * @param webServiceUrl
   * @param oauthUrl
   */
  public static void init(String appId,
                          String appSecret,
                          String webServiceUrl,
                          String oauthUrl) {
    if (inst != null) {
      return;
    }

    inst = new JsydfwClient();
    inst.appId = appId;
    inst.appSecret = appSecret;
    inst.webServiceUrl = webServiceUrl;
    inst.oauthUrl = oauthUrl;
  }

  /**
   * 初始化后置应用通讯客户端
   * @param appId
   * @param appSecret
   * @param webServiceUrl
   * @param userInfoUrl
   */
  public static void postInit(String appId,
                          String appSecret,
                          String webServiceUrl,
                          String userInfoUrl) {
    if (inst != null) {
      return;
    }

    inst = new JsydfwClient();
    inst.appId = appId;
    inst.appSecret = appSecret;
    inst.webServiceUrl = webServiceUrl;
    inst.userInfoUrl = userInfoUrl;
  }

  public static void postInit(String appId,
                              String appSecret,
                              String webServiceUrl,
                              String userInfoUrl,
                              String lxMessageUrl,
                              String agentId) {
    postInit(appId, appSecret, webServiceUrl, userInfoUrl);
    inst.lxMessageUrl = lxMessageUrl;
    inst.agentId = agentId;
  }

  // 输入参数
  private String appId; // 应用ID
  private String appSecret; // 应用Secret
  private String webServiceUrl; // 移动服务接口URL
  private String oauthUrl; // oauth认证Url
  private String userInfoUrl; // 用户信息服务URL
  private String lxMessageUrl; // 蓝信信息服务URL
  private String appMessageUrl; // 蓝信应用信息服务URL
  private String agentId; // 蓝信消息公众号ID

  // 输出参数

  /**
   * 代理http请求，以json格式返回数据
   * @param url
   * @param params
   * @return
   */
  private JSONObject httpJsonRequest(String url, Map params) {

    JSONObject resultJson = this.requestJsonByhttpPostForm(url, params);

    String errorCode = resultJson.getStr("errcode");
    String errorMsg = resultJson.getStr("errmsg");

    if (!errorCode.equals("0")) {
      throw new JsydfwException(errorCode, errorMsg);
    }

    if (resultJson.containsKey("content")) {
      String contentSrc = resultJson.getStr("content").replaceAll("\n", "");
      _log.debug("The result source content is {}", contentSrc);
      String jsonStr = Base64.decodeStr(contentSrc);
      _log.debug("The result json content is {}", jsonStr);
      resultJson.put("content", JSONUtil.parseObj(jsonStr));
    }

    return resultJson;
  }

  private Map createParamsMap(String url,
                              JSONObject header,
                              String userId,
                              String deviceId) {
    HashMap<String, Object> paramMap = new HashMap<>();
    paramMap.put("url", url);
    if (header == null) {
      header = new JSONObject();
    }

    if(!header.containsKey("Content-Type")) {
      header.put("Content-Type", "application/json");
    }

    paramMap.put("header", header.toString());
    paramMap.put("token", getToken());
    paramMap.put("userid", userId);
    paramMap.put("deviceid", deviceId);

    return paramMap;
  }

  /**
   * 代理GET请求数据, 以json格式返回数据，支持文件下载
   * @return
   */
  public JSONObject httpJsonGetRequest(String url,
                                       JSONObject header,
                                       String userId,
                                       String deviceId) {

    Map paramMap = createParamsMap(url, header, userId, deviceId);
    return httpJsonRequest(webServiceUrl + "?action=httpJsonGetRequest", paramMap);
  }

  public JSONObject httpJsonPostRequestByStream(String url,
                                       JSONObject header,
                                       String content,
                                       String userId,
                                       String deviceId) {

    Map paramMap = createParamsMap(url, header, userId, deviceId);
    paramMap.put("content", content);
    return httpJsonRequest(webServiceUrl + "?action=httpJsonPostRequestByStream", paramMap);
  }

  public JSONObject httpJsonPostRequestByStream(String url,
                                       String content,
                                       JSONObject userInfo) {
    return httpJsonPostRequestByStream(url, null, content, userInfo.getStr("userId"), userInfo.getStr("deviceId"));
  }

  public JSONObject httpJsonGetRequest(String url,
                                       JSONObject userInfo) {
    return httpJsonGetRequest(url, null, userInfo.getStr("userId"), userInfo.getStr("deviceId"));
  }

  private void updateToken() {
    synchronized (inst) {
      if(token == null || System.currentTimeMillis() + 60 * 1000 > tokenExpiredTime) {
        _log.info("Update token in thread {}", Thread.currentThread().getName());
        HashMap<String, Object> paramMap = new HashMap<>();
        paramMap.put("appid", appId);
        paramMap.put("secret", appSecret);

        JSONObject resultJson = this.requestJsonByhttpPostForm(webServiceUrl + "?action=getToken", paramMap);

        String errorCode = resultJson.getStr("errcode");
        String errorMsg = resultJson.getStr("errmsg");
        if (!errorCode.equals("T1010")) {
          throw new JsydfwException(errorCode, errorMsg);
        }

        token = resultJson.getStr("token");
        tokenExpiredTime = System.currentTimeMillis()
          + resultJson.getLong("expires_time", 7200L) * 1000L;
        _log.info("Updated token to {} in thread {}", token, Thread.currentThread().getName());
      }
    }
  }

  /**
   * 获取Token
   *  1. Token为空或者1分钟内即将到期，获取token
   * @return
   */
  public String getToken() {
    if(token == null || System.currentTimeMillis() + 60 * 1000 > tokenExpiredTime) {
      _log.info("Go to update token in thread {}", Thread.currentThread().getName());
      this.updateToken();
    }

    return token;
  }

  /**
   * 发送文本消息给用户
   * @param toUsers 用户列表，逗号隔开
   * @param content 消息内容
   */
  public void sendTextMsgToUsers(String toUsers, String content) {
    JSONObject text = new JSONObject();
    text.put("content", content);

    JSONObject params = new JSONObject();
    params.put("touser", toUsers);
    params.put("agentid", agentId);
    params.put("msgtype", "text");
    params.put("text", text);

    JSONObject resultJson = this.requestJsonByhttpPostStr(lxMessageUrl
      + "?action=sendMsg&access_token=" + getToken(), params.toString());

    String errorCode = resultJson.getStr("errcode");
    String errorMsg = resultJson.getStr("errmsg");

    if (!errorCode.equals("0")) {
      throw new JsydfwException(errorCode, errorMsg);
    }
  }

  /**
   * 通过 Http Post提交表单数据 获取 json数据
   * @param url
   * @param params
   * @return
   */
  private JSONObject requestJsonByhttpPostForm(String url, Map params) {
    _log.debug("The http post form: {},{}", url, params);
    String result = HttpUtil.post(url, params);
    _log.debug("The http post form: {},{}\n json result is: \n{}", url, params, result);
    JSONObject resultJson = JSONUtil.parseObj(result);
    return resultJson;
  }

  /**
   * 通过 Http Post String 数据(json/xml) 获取 json数据
   * @param url
   * @param body
   * @return
   */
  private JSONObject requestJsonByhttpPostStr(String url, String body) {
    _log.debug("The http post form: {},{}", url, body);
    String result = HttpUtil.post(url, body);
    _log.debug("The http post string: {},{}\n json result is: \n{}", url, body, result);
    JSONObject resultJson = JSONUtil.parseObj(result);
    return resultJson;
  }

  /**
   * 通过 Http Get 请求 获取 json 数据
   * @param url
   * @param params
   * @return
   */
  private JSONObject requestJsonByhttpGet(String url, Map params) {
    _log.debug("The http get: {},{}", url, params);
    String result = HttpUtil.get(url, params);
    _log.debug("The http get: {},{}\n json result is: \n{}", url, params, result);
    JSONObject resultJson = JSONUtil.parseObj(result);
    return resultJson;
  }

  /**
   * 获取蓝信用户信息
   * @param userId
   * @param deviceId
   * @return
   */
  public JSONObject getUserInfoById(String userId,
                                    String deviceId) {
    HashMap<String, Object> paramMap = new HashMap<>();
    paramMap.put("action", "getUserInfoById");
    paramMap.put("userId", userId);
    paramMap.put("deviceId", deviceId);
    paramMap.put("access_token", getToken());

    JSONObject resultJson = this.requestJsonByhttpGet(userInfoUrl, paramMap);

    String errorCode = resultJson.getStr("errcode");
    String errorMsg = resultJson.getStr("errmsg");

    if (!errorCode.equals("U1999")) {
      throw new JsydfwException(errorCode, errorMsg);
    }

    return resultJson.getJSONObject("data");
  }

  /**
   * 获取用户OAuth信息
   * @return
   */
  public JSONObject getAuthInfo(String code) {
    HashMap<String, Object> paramMap = new HashMap<>();
    paramMap.put("appid", appId);
    paramMap.put("access_token", getToken());
    paramMap.put("code", code);

    JSONObject resultJson = this.requestJsonByhttpGet(oauthUrl, paramMap);

    String errorCode = resultJson.getStr("errorCode");
    String errorMsg = resultJson.getStr("errorMsg");

    if (!errorCode.equals("0")) {
      throw new JsydfwException(errorCode, errorMsg);
    }

    return resultJson;
  }

  // 中间数据
  private String token = null; // 当前的access token
  private long tokenExpiredTime; // 当前access token的过期时间, 单位毫秒

  private JsydfwClient() {}

}
